package common.service.impl;

import cn.hutool.core.exceptions.ExceptionUtil;
import common.config.redisson.RedisCacheConstants;
import common.model.converter.CacheInfoConverter;
import common.model.dto.UserCacheInfo;
import common.model.enums.BusinessCodeValidEnum;
import common.model.enums.UserDeletedEnum;
import common.model.po.*;
import common.model.response.base.Result;
import common.service.*;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RList;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 在这里填写类的功能描述
 *
 * @author 米泽鹏
 * @since 2022-11-29 下午 7:14
 */
@Service
@Slf4j
public class RedissonCacheServiceImpl implements RedissonCacheService {

	@Resource
	private CommonSysUserService userService;
	@Resource
	private CommonSysAuthorityService authorityService;
	@Resource
	private CommonSysUserRoleService userRoleService;
	@Resource
	private CommonSysRoleService roleService;
	@Resource
	private CommonSysRoleAuthorityService roleAuthorityService;
	@Resource
	private CommonSysBusinessCodeService commonSysBusinessCode2Service;
	@Resource
	private CommonSysBusinessCodeDetailService commonSysBusinessCodeDetailService;
	@Resource
	private RedissonClient redissonClient;

	@Override
	public String getLoginTokenStringByUserId(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.LOGIN_TOKEN_CACHE);
		return tokenInfoMap.get(userId);
	}

	@Override
	public Result<Boolean> cacheLoginTokenString(Long userId, String token, Date expireDate) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.LOGIN_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastPut(userId, token, expireDate.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS));
	}

	@Override
	public Result<Long> removeLoginTokenStringByUserId(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.LOGIN_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastRemove(userId));
	}

	@Override
	public List<UserCacheInfo> getSysUserCache() {
		return redissonClient.getList(RedisCacheConstants.SYS_USER_CACHE);
	}

	@Override
	public Result<?> cacheSysUser() {
		return cacheSysUser(userService.lambdaQuery().eq(SysUser::getIsDeleted, UserDeletedEnum.NOT_DELETED.getValue()).last("lock in share mode").list());
	}

	@Override
	public Result<?> cacheSysUser(List<SysUser> userList) {
		try {
			log.info("更新用户缓存");
			RList<UserCacheInfo> list = redissonClient.getList(RedisCacheConstants.SYS_USER_CACHE);
			list.clear();
			list.addAll(userList.stream().filter(user -> UserDeletedEnum.NOT_DELETED.getValue().equals(user.getIsDeleted())).map(CacheInfoConverter::userPoToUserValidCacheInfo).collect(Collectors.toList()));
			return Result.success();
		} catch (Throwable t) {
			log.error(ExceptionUtil.getRootCauseMessage(t), t);
			return Result.error(t);
		}
	}

	@Override
	public List<SysAuthority> getSysAuthorityCache() {
		return redissonClient.getList(RedisCacheConstants.SYS_AUTHORITY_CACHE);
	}

	@Override
	public Result<?> cacheSysAuthority() {
		List<SysAuthority> authorityList = authorityService.lambdaQuery().last("lock in share mode").list();
		return cacheSysAuthority(authorityList);
	}

	@Override
	public Result<?> cacheSysAuthority(List<SysAuthority> authorityList) {
		try {
			log.info("更新权限缓存");
			RList<SysAuthority> list = redissonClient.getList(RedisCacheConstants.SYS_AUTHORITY_CACHE);
			list.clear();
			list.addAll(authorityList);
			return Result.success();
		} catch (Throwable t) {
			log.error(ExceptionUtil.getRootCauseMessage(t), t);
			return Result.error(t);
		}
	}

	@Override
	public RMap<Long, Set<Long>> getAllUserIdCacheByRoleId() {
		return redissonClient.getMap(RedisCacheConstants.USER_ID_CACHE_BY_ROLE_ID);
	}

	@Override
	public RMap<Long, Set<Long>> getAllRoleIdCacheByUserId() {
		return redissonClient.getMap(RedisCacheConstants.ROLE_ID_CACHE_BY_USER_ID);
	}

	@Override
	public Result<?> cacheSysUserRole() {
		List<SysUserRole> userRoleList = userRoleService.getAllSysUserRole();
		return cacheSysUserRole(userRoleList);
	}

	@Override
	public Result<?> cacheSysUserRole(List<SysUserRole> userRoleList) {
		try {
			log.info("更新用户-角色缓存");
			RMap<Long, Set<Long>> cacheMapByRoleId = redissonClient.getMap(RedisCacheConstants.USER_ID_CACHE_BY_ROLE_ID);
			RMap<Long, Set<Long>> cacheMapByUserId = redissonClient.getMap(RedisCacheConstants.ROLE_ID_CACHE_BY_USER_ID);
			cacheMapByRoleId.clear();
			cacheMapByUserId.clear();
			Map<Long, Set<Long>> byRoleIdMap = userRoleList.stream().collect(Collectors.groupingBy(SysUserRole::getRoleId, Collectors.mapping(SysUserRole::getUserId, Collectors.toSet())));
			Map<Long, Set<Long>> byUserIdMap = userRoleList.stream().collect(Collectors.groupingBy(SysUserRole::getUserId, Collectors.mapping(SysUserRole::getRoleId, Collectors.toSet())));
			for (Map.Entry<Long, Set<Long>> entry : byRoleIdMap.entrySet()) {
				cacheMapByRoleId.fastPut(entry.getKey(), entry.getValue());
			}
			for (Map.Entry<Long, Set<Long>> entry : byUserIdMap.entrySet()) {
				cacheMapByUserId.fastPut(entry.getKey(), entry.getValue());
			}
			return Result.success();
		} catch (Throwable t) {
			log.error(ExceptionUtil.getRootCauseMessage(t), t);
			return Result.error(t);
		}
	}

	@Override
	public List<SysRole> getSysRoleCache() {
		return redissonClient.getList(RedisCacheConstants.SYS_ROLE_CACHE);
	}

	@Override
	public Result<?> cacheSysRole() {
		List<SysRole> userRoleList = roleService.lambdaQuery().last("lock in share mode").list();
		return cacheSysRole(userRoleList);
	}

	@Override
	public Result<?> cacheSysRole(List<SysRole> roleList) {
		try {
			log.info("更新角色缓存");
			RList<SysRole> list = redissonClient.getList(RedisCacheConstants.SYS_ROLE_CACHE);
			list.clear();
			list.addAll(roleList);
			return Result.success();
		} catch (Throwable t) {
			log.error(ExceptionUtil.getRootCauseMessage(t), t);
			return Result.error(t);
		}
	}

	@Override
	public RMap<Long, Set<Long>> getAllAuthIdCacheByRoleId() {
		return redissonClient.getMap(RedisCacheConstants.AUTH_ID_CACHE_BY_ROLE_ID);
	}

	@Override
	public RMap<Long, Set<Long>> getAllRoleIdCacheByAuthId() {
		return redissonClient.getMap(RedisCacheConstants.ROLE_ID_CACHE_BY_AUTH_ID);
	}

	@Override
	public Result<?> cacheSysRoleAuthority() {
		List<SysRoleAuthority> roleAuthorityList = roleAuthorityService.lambdaQuery().last("lock in share mode").list();
		return cacheSysRoleAuthority(roleAuthorityList);
	}

	@Override
	public Result<?> cacheSysRoleAuthority(List<SysRoleAuthority> roleAuthorityList) {
		try {
			log.info("更新角色-权限缓存");
			RMap<Long, Set<Long>> cacheMapByRoleId = redissonClient.getMap(RedisCacheConstants.AUTH_ID_CACHE_BY_ROLE_ID);
			RMap<Long, Set<Long>> cacheMapByAuthId = redissonClient.getMap(RedisCacheConstants.ROLE_ID_CACHE_BY_AUTH_ID);
			cacheMapByRoleId.clear();
			cacheMapByAuthId.clear();
			Map<Long, Set<Long>> byRoleIdMap = roleAuthorityList.stream().collect(Collectors.groupingBy(SysRoleAuthority::getRoleId, Collectors.mapping(SysRoleAuthority::getAuthId, Collectors.toSet())));
			Map<Long, Set<Long>> byAuthIdMap = roleAuthorityList.stream().collect(Collectors.groupingBy(SysRoleAuthority::getAuthId, Collectors.mapping(SysRoleAuthority::getRoleId, Collectors.toSet())));
			for (Map.Entry<Long, Set<Long>> entry : byRoleIdMap.entrySet()) {
				cacheMapByRoleId.fastPut(entry.getKey(), entry.getValue());
			}
			for (Map.Entry<Long, Set<Long>> entry : byAuthIdMap.entrySet()) {
				cacheMapByAuthId.fastPut(entry.getKey(), entry.getValue());
			}
			return Result.success();
		} catch (Throwable t) {
			log.error(ExceptionUtil.getRootCauseMessage(t), t);
			return Result.error(t);
		}
	}

	@Override
	public List<SysBusinessCode> getSysBusinessCodeCache() {
		return redissonClient.getList(RedisCacheConstants.SYS_BUSINESS_CODE_CACHE);
	}

	@Override
	public List<SysBusinessCodeDetail> getSysBusinessCodeDetailCache() {
		return redissonClient.getList(RedisCacheConstants.SYS_BUSINESS_CODE_DETAIL_CACHE);
	}

	@Override
	public Result<?> cacheSysBusinessCode() {
		try {
			log.info("更新业务编码缓存");
			List<SysBusinessCode> businessCodeList = commonSysBusinessCode2Service.lambdaQuery().eq(SysBusinessCode::getValid, BusinessCodeValidEnum.VALID.getValue()).last("lock in share mode").list();
			List<SysBusinessCodeDetail> businessCodeDetailList = commonSysBusinessCodeDetailService.lambdaQuery().in(SysBusinessCodeDetail::getBusinessCodeId, businessCodeList.stream().map(SysBusinessCode::getId).collect(Collectors.toSet())).last("lock in share mode").list();
			RList<SysBusinessCode> businessCodeRList = redissonClient.getList(RedisCacheConstants.SYS_BUSINESS_CODE_CACHE);
			RList<SysBusinessCodeDetail> businessCodeDetailRList = redissonClient.getList(RedisCacheConstants.SYS_BUSINESS_CODE_DETAIL_CACHE);
			businessCodeRList.clear();
			businessCodeDetailRList.clear();
			businessCodeRList.addAll(businessCodeList);
			businessCodeDetailRList.addAll(businessCodeDetailList);
			return Result.success();
		} catch (Throwable t) {
			log.error(ExceptionUtil.getRootCauseMessage(t), t);
			return Result.error(t);
		}
	}

	@Override
	public String getModifyPasswordTokenStringByUserId(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.MODIFY_PASSWORD_TOKEN_CACHE);
		return tokenInfoMap.get(userId);
	}

	@Override
	public Result<Boolean> cacheModifyPasswordTokenString(Long userId, String token, Date expireDate) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.MODIFY_PASSWORD_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastPut(userId, token, expireDate.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS));
	}

	@Override
	public Result<Long> removeModifyPasswordTokenString(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.MODIFY_PASSWORD_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastRemove(userId));
	}

	@Override
	public String getActivateEmailTokenStringByUserId(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.ACTIVATE_EMAIL_TOKEN_CACHE);
		return tokenInfoMap.get(userId);
	}

	@Override
	public Result<Boolean> cacheActivateEmailTokenString(Long userId, String token, Date expireDate) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.ACTIVATE_EMAIL_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastPut(userId, token, expireDate.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS));
	}

	@Override
	public Result<Long> removeActivateEmailTokenString(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.ACTIVATE_EMAIL_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastRemove(userId));
	}

	@Override
	public String getModifyEmailTokenStringByUserId(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.MODIFY_EMAIL_TOKEN_CACHE);
		return tokenInfoMap.get(userId);
	}

	@Override
	public Result<Boolean> cacheModifyEmailTokenString(Long userId, String token, Date expireDate) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.MODIFY_EMAIL_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastPut(userId, token, expireDate.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS));
	}

	@Override
	public Result<Long> removeModifyEmailTokenString(Long userId) {
		RMapCache<Long, String> tokenInfoMap = redissonClient.getMapCache(RedisCacheConstants.MODIFY_EMAIL_TOKEN_CACHE);
		return Result.successWithData(tokenInfoMap.fastRemove(userId));
	}

}
